package com.bluesky.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bluesky.common.bo.DictModel;
import com.bluesky.common.enums.StatusEnum;
import com.bluesky.common.exception.CustomException;
import com.bluesky.common.utils.DictUtils;
import com.bluesky.system.common.dto.SysDictAddDTO;
import com.bluesky.system.common.dto.SysDictEditDTO;
import com.bluesky.system.common.dto.SysDictQueryDTO;
import com.bluesky.system.entity.SysDict;
import com.bluesky.system.entity.SysDictItem;
import com.bluesky.system.mapper.SysDictMapper;
import com.bluesky.system.service.ISysDictItemService;
import com.bluesky.system.service.ISysDictService;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 字典表 服务实现类
 * </p>
 *
 * @author Kevin
 * @since 2021-06-10
 */
@Service
public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> implements ISysDictService {

    @Resource
    private ISysDictItemService sysDictItemService;

    @Override
    public IPage<SysDict> page(Page reqPage, SysDictQueryDTO req) {
        LambdaQueryWrapper<SysDict> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getDictCode()), SysDict::getDictCode, req.getDictCode());
        queryWrapper.like(StrUtil.isNotBlank(req.getDictName()), SysDict::getDictName, req.getDictName());
        queryWrapper.orderByDesc(SysDict::getCreateTime);
        return this.page(reqPage, queryWrapper);
    }

    @Override
    public List<SysDict> list(SysDictQueryDTO req) {
        LambdaQueryWrapper<SysDict> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StrUtil.isNotBlank(req.getDictCode()), SysDict::getDictCode, req.getDictCode());
        queryWrapper.like(StrUtil.isNotBlank(req.getDictName()), SysDict::getDictName, req.getDictName());
        queryWrapper.orderByDesc(SysDict::getCreateTime);
        return this.list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysDictAddDTO req) {
        if (!this.checkUniquedictName(req.getDictName(), null)) {
            throw new CustomException("字典名称已存在");
        }
        if (!this.checkUniqueDictCode(req.getDictCode(), null)) {
            throw new CustomException("字典编码已存在");
        }
        SysDict entity = BeanUtil.copyProperties(req, SysDict.class);
        this.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysDictEditDTO req) {
        if (!this.checkUniquedictName(req.getDictName(), req.getId())) {
            throw new CustomException("字典名称已存在");
        }
        if (!this.checkUniqueDictCode(req.getDictCode(), req.getId())) {
            throw new CustomException("字典编码已存在");
        }
        SysDict entity = BeanUtil.copyProperties(req, SysDict.class);
        this.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(String ids) {
        List<String> idList = Arrays.asList(ids.split(","));
        this.removeByIds(idList);
        idList.forEach(item -> {
            sysDictItemService.remove(Wrappers.lambdaQuery(SysDictItem.class).eq(SysDictItem::getDictId, item));
        });
    }

    @Override
    public SysDict view(String id) {
        return this.getById(id);
    }

    @Override
    public List<DictModel> listDictModel(String dictCode) {
        List<DictModel> dictModelListCache = DictUtils.getDictList(dictCode);
        if (!dictModelListCache.isEmpty()) {
            return dictModelListCache;
        }
        SysDict sysDict = this.getOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictCode, dictCode).eq(SysDict::getStatus, StatusEnum.YES.getCode()));
        if (Objects.isNull(sysDict)) {
            return Lists.newArrayList();
        }
        List<SysDictItem> sysDictItemList = sysDictItemService.list(Wrappers.lambdaQuery(SysDictItem.class).eq(SysDictItem::getDictId, sysDict.getId()).eq(SysDictItem::getStatus, StatusEnum.YES.getCode()).orderByAsc(SysDictItem::getSort));
        List<DictModel> dictModelList = sysDictItemList.stream().map(item -> new DictModel().setLabel(item.getDictItemName()).setValue(item.getDictItemCode())).collect(Collectors.toList());
        DictUtils.setDictCache(sysDict.getDictCode(), dictModelList);
        return dictModelList;
    }

    @Override
    public void loadAllDictCache() {
        DictUtils.clearDictCache();
        List<SysDict> sysDictList = this.list(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getStatus, StatusEnum.YES.getCode()));
        sysDictList.forEach(temp -> {
            List<SysDictItem> sysDictItemList = sysDictItemService.list(Wrappers.lambdaQuery(SysDictItem.class).eq(SysDictItem::getDictId, temp.getId()).eq(SysDictItem::getStatus, StatusEnum.YES.getCode()).orderByAsc(SysDictItem::getSort));
            List<DictModel> dictModelList = sysDictItemList.stream().map(item -> new DictModel().setLabel(item.getDictItemName()).setValue(item.getDictItemCode())).collect(Collectors.toList());
            DictUtils.setDictCache(temp.getDictCode(), dictModelList);
        });
    }

    private Boolean checkUniquedictName(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysDict entity = this.getOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictName, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

    private Boolean checkUniqueDictCode(String value, Long id) {
        if (StrUtil.isBlank(value)) {
            return true;
        }
        id = Objects.isNull(id) ? -1L : id;
        SysDict entity = this.getOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictCode, value));
        return Objects.isNull(entity) || entity.getId().longValue() == id.longValue();
    }

}
